package tech.yangzhijie.basic.knowledge.mianshi;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * CAS算法只能满足原子性但会有ABA问题
 */
public class Test07CompareAndSwapABA {


    public static void main(String[] args) {
       simulation_ABA_Problem();

       simulation_ABA_solve();
    }

    /**
     * 最终结果 200
     * 实际要求 无法修改 还是1
     */
    public static void simulation_ABA_Problem(){
        CompareAndSwapABADemo01 demo = new CompareAndSwapABADemo01();
        CountDownLatch countDownLatch = new CountDownLatch(2);

        new Thread(()->{
            demo.getAtomicInteger().compareAndSet(1,100);
            demo.getAtomicInteger().compareAndSet(100,1);
            countDownLatch.countDown();
        },"T1").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            demo.getAtomicInteger().compareAndSet(1,200);
            countDownLatch.countDown();
        },"T2").start();

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终结果: " + demo.getAtomicInteger().get());
    }

    public static void simulation_ABA_solve(){
        CompareAndSwapABADemo01 demo = new CompareAndSwapABADemo01();
        CountDownLatch countDownLatch = new CountDownLatch(2);

        new Thread(()->{
            AtomicInteger atomicInteger = new AtomicInteger(300);
            demo.getIntReference().compareAndSet(demo.getAtomicInteger(),atomicInteger,1,2);
            demo.getIntReference().compareAndSet(atomicInteger,demo.getAtomicInteger(),2,3);

            countDownLatch.countDown();
        },"T1").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            demo.getIntReference().compareAndSet(demo.getAtomicInteger(),new AtomicInteger(400),1,2);
            countDownLatch.countDown();
        },"T2").start();

        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终结果: " + demo.getAtomicInteger().get() + "\t 版本号: " + demo.getIntReference().getStamp());
    }
}

class CompareAndSwapABADemo01 {

    private AtomicInteger atomicInteger = new AtomicInteger(1);

    private AtomicStampedReference<AtomicInteger> intReference = new AtomicStampedReference<>(atomicInteger,1);

    public AtomicInteger getAtomicInteger() {
        return atomicInteger;
    }

    public AtomicStampedReference<AtomicInteger> getIntReference() {
        return intReference;
    }
}